using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;
using Omu.ValueInjecter;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" DeliveryOrder to change the class name "DeliveryOrderServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class DeliveryOrderServices : IDeliveryOrderServices
    {
        private readonly DeliveryOrderRepository DeliveryOrderRepository;
        private readonly SalesOrderRepository _SORepository;
        private readonly SpkRepository _SpkRepository;
        private readonly InventoryWarehouseRepository _iwRepository;
        private readonly MutasiStokRepository _mutasiStokRepository;
        private readonly WcfSessionStorage _session;
        private InventoryRepository InventoryRep;
        private SalesInvoiceRepository SIRep;
        private AppParamRepository paramRepository;

        public DeliveryOrderServices()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            _session = new WcfSessionStorage();
            DeliveryOrderRepository = new DeliveryOrderRepository(_session);
            InventoryRep = new InventoryRepository(_session);
            _mutasiStokRepository = new MutasiStokRepository(_session);
            _iwRepository = new InventoryWarehouseRepository(_session);
            _SORepository = new SalesOrderRepository(_session);
            _SpkRepository = new SpkRepository(_session);
            SIRep = new SalesInvoiceRepository(_session);
            paramRepository = new AppParamRepository(_session);
        }

        #region IDeliveryOrderServices Members

        public List<DeliveryOrderDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                              string sortType = "ASC")
        {
            var DeliveryOrders = new List<DeliveryOrder>();
            var Results = new List<DeliveryOrderDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                DeliveryOrders = DeliveryOrderRepository.GetDataPaged(page, 30, "DODate", "DESC").ToList();
            }
            else
            {
                DeliveryOrders = DeliveryOrderRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = DeliveryOrderRepository.RecordCount;

            foreach (var d in DeliveryOrders)
            {
                var Dto = new DeliveryOrderDTO();
                Dto.DONo = d.DONo;
                Dto.DODate = d.DODate;
                Dto.Description = d.Description;
                Dto.DeliveryAddress = d.DeliveryAddress;
                Dto.CustomerName = d.CustomerName;
                Dto.Address = d.Address;
                Dto.Telp = d.Telp;
                Dto.SONo = d.SONo;
                Dto.Status = (Status) d.Status;
                Dto.PSNo = d.PSNo;
                Dto.SINo = d.SINo;
                Results.Add(Dto);
            }

            return Results;
        }

        public bool Save(DeliveryOrderDTO DeliveryOrderDTO)
        {
            bool res;
            bool IsNew = false;
            try
            {
                DeliveryOrder DeliveryOrder = DeliveryOrderRepository.GetDataOne(x => x.DONo == DeliveryOrderDTO.DONo);
                var paramRounded = paramRepository.GetDataOne(x => x.AppParamName == "BatasRound");
                Decimal batasRounded = Decimal.Parse(paramRounded.AppParamValue);

                if (DeliveryOrder == null)
                {
                    DeliveryOrder = new DeliveryOrder();
                    IsNew = true;
                }

                DeliveryOrderRepository
                    .ExecuteTransactionNative(() =>
                                                  {

                                                      if (IsNew)
                                                      {
                                                          Mapper.Map(DeliveryOrderDTO, DeliveryOrder);
                                                          //Untuk New entry dari transaksi bukan dari email
                                                          if (String.IsNullOrEmpty(DeliveryOrder.DONo))
                                                                DeliveryOrder.DONo = GetLastDONo(DeliveryOrderDTO.CostCenter);
                                                          foreach (DeliveryOrderDetail deliveryOrderDetail in
                                                           DeliveryOrder.DeliveryOrderDetails)
                                                          {
                                                              deliveryOrderDetail.DeliveryOrder = DeliveryOrder;
                                                              deliveryOrderDetail.DeliveryOrderDetailId = 0;
                                                              deliveryOrderDetail.Warehouse = DeliveryOrder.Warehouse;
                                                              if (deliveryOrderDetail.Inventory.Item.IsStock)
                                                              {
                                                                  //Mutasi Keluar
                                                                  var mutasiStok = new MutasiStok();
                                                                  mutasiStok.SerialNumber =
                                                                      deliveryOrderDetail.Inventory.SerialNumber;
                                                                  mutasiStok.ReferenceNumber = DeliveryOrder.DONo;
                                                                  mutasiStok.TglMutasi = DeliveryOrder.DODate.ToDateTimeSell();
                                                                  mutasiStok.Type = DeliveryOrder.GetType().Name;
                                                                  mutasiStok.QtyKeluar = deliveryOrderDetail.QtyUnit;
                                                                  mutasiStok.PanjangKeluar = deliveryOrderDetail.Panjang;
                                                                  mutasiStok.LebarKeluar = deliveryOrderDetail.Lebar;
                                                                  MutasiStok mutasiLast =
                                                                      _mutasiStokRepository.FindLastMutasi(
                                                                          mutasiStok.SerialNumber,
                                                                          deliveryOrderDetail.Warehouse.KodeWarehouse
                                                                          ,mutasiStok.TglMutasi
                                                                          );

                                                                  if (deliveryOrderDetail.Inventory.Item.IsRounded)
                                                                      mutasiLast.QtySisa = Math.Round(
                                                                          mutasiLast.QtySisa, 2, MidpointRounding.AwayFromZero);
                                                                  mutasiStok.QtySisa = mutasiLast.QtySisa -
                                                                                       mutasiStok.QtyKeluar;
                                                                  mutasiStok.SheetKeluar = deliveryOrderDetail.Tinggi;
                                                                  mutasiStok.SheetSisa = mutasiLast.SheetSisa -
                                                                                         mutasiStok.SheetKeluar;
                                                                  mutasiStok.PanjangSisa = mutasiLast.PanjangSisa -
                                                                                        mutasiStok.PanjangKeluar;
                                                                  mutasiStok.LebarSisa = mutasiLast.LebarSisa -
                                                                                         mutasiStok.LebarKeluar;
                                                                                        
                                                                  mutasiStok.KodeWarehouse =
                                                                      deliveryOrderDetail.Warehouse.KodeWarehouse;
                                                                  if (mutasiStok.QtySisa < 0)
                                                                      throw new Exception(mutasiStok.SerialNumber + " Stok Tidak Mencukupi!");
                                                                  if (deliveryOrderDetail.Inventory.Item.IsRounded)
                                                                      if (mutasiStok.QtySisa < batasRounded)
                                                                          mutasiStok.QtySisa = 0;
                                                                  _mutasiStokRepository.SaveOrUpdate(mutasiStok,deliveryOrderDetail.Inventory.KodePallet);

                                                              }
                                                          }
                                                          DeliveryOrderRepository.SaveOrUpdate(DeliveryOrder);
                                                      }
                                                      else
                                                      {
                                                          //Jika Status Void dan Close tdk boleh Update
                                                          if (DeliveryOrder.Status == (int)Status.Void || DeliveryOrder.Status == (int)Status.Close)
                                                              throw new Exception("Tidak bisa di Update Status sudah Close atau Void!");

                                                          DeliveryOrderRepository.Delete(DeliveryOrder);
                                                          var DO = new DeliveryOrder();
                                                          DO.modified_date = DateTime.Now;
                                                          DO.created_date = DeliveryOrder.created_date;
                                                          Mapper.Map(DeliveryOrderDTO, DO);
                                                          foreach (var doDetail in DO.DeliveryOrderDetails)
                                                              doDetail.DeliveryOrder = DO;
                                                          DeliveryOrderRepository.Session.SaveOrUpdateCopy(DO);

                                                          var mutasiStokSaatItu =
                                                              _mutasiStokRepository.GetDataOne(
                                                                  x => x.ReferenceNumber == DeliveryOrder.DONo);

                                                          DateTime currDate = DateTime.Now;

                                                          if (mutasiStokSaatItu != null)
                                                              currDate = mutasiStokSaatItu.TglMutasi;

                                                          _mutasiStokRepository.DeleteMutasiStok(DeliveryOrder.DONo);
                                                          foreach (DeliveryOrderDetail deliveryOrderDetail in
                                                           DO.DeliveryOrderDetails)
                                                          {
                                                              deliveryOrderDetail.Warehouse = DeliveryOrder.Warehouse;
                                                              if (deliveryOrderDetail.Inventory.Item.IsStock)
                                                              {
                                                                  //Mutasi Keluar
                                                                  var mutasiStok = new MutasiStok();
                                                                  mutasiStok.SerialNumber =
                                                                      deliveryOrderDetail.Inventory.SerialNumber;
                                                                  mutasiStok.ReferenceNumber = DeliveryOrder.DONo;
                                                                  mutasiStok.TglMutasi = currDate.ToDateTimeSell();
                                                                  mutasiStok.Type = DeliveryOrder.GetType().Name;
                                                                  mutasiStok.QtyKeluar = deliveryOrderDetail.QtyUnit;
                                                                  mutasiStok.PanjangKeluar = deliveryOrderDetail.Panjang;
                                                                  mutasiStok.LebarKeluar = deliveryOrderDetail.Lebar;
                                                                  MutasiStok mutasiLast =
                                                                      _mutasiStokRepository.FindLastMutasi(
                                                                          mutasiStok.SerialNumber,
                                                                          deliveryOrderDetail.Warehouse.KodeWarehouse
                                                                          ,mutasiStok.TglMutasi
                                                                          );

                                                                  if (deliveryOrderDetail.Inventory.Item.IsRounded)
                                                                      mutasiLast.QtySisa = Math.Round(
                                                                          mutasiLast.QtySisa, 2, MidpointRounding.AwayFromZero);

                                                                  mutasiStok.QtySisa = mutasiLast.QtySisa -
                                                                                       mutasiStok.QtyKeluar;
                                                                  mutasiStok.SheetKeluar = deliveryOrderDetail.Tinggi;
                                                                  mutasiStok.SheetSisa = mutasiLast.SheetSisa -
                                                                                         mutasiStok.SheetKeluar;
                                                                  mutasiStok.PanjangSisa = mutasiLast.PanjangSisa -
                                                                                       mutasiStok.PanjangKeluar;
                                                                  mutasiStok.LebarSisa = mutasiLast.LebarSisa -
                                                                                         mutasiStok.LebarKeluar;
                                                                  mutasiStok.KodeWarehouse =
                                                                      deliveryOrderDetail.Warehouse.KodeWarehouse;

                                                                  if (mutasiStok.QtySisa < 0)
                                                                      throw new Exception(mutasiStok.SerialNumber + " Stok Tidak Mencukupi!");

                                                                  if (deliveryOrderDetail.Inventory.Item.IsRounded)
                                                                        if (mutasiStok.QtySisa < batasRounded)
                                                                                 mutasiStok.QtySisa = 0;
                                                                  _mutasiStokRepository.SaveOrUpdate(mutasiStok,deliveryOrderDetail.Inventory.KodePallet);
                                                              }
                                                          }
                                                      }

                                                     
                                                      if (DeliveryOrderDTO.SalesOrder != null)
                                                      {
                                                          SalesOrder so =
                                                              _SORepository.GetDataOne(
                                                                  x => x.SONo == DeliveryOrderDTO.SalesOrder.SONo);
                                                          so.Status = Convert.ToInt16(Status.Close);
                                                          _SORepository.SaveOrUpdate(so);
                                                      }

                                                      if (DeliveryOrderDTO.Spk != null)
                                                      {
                                                          Spk spk =
                                                              _SpkRepository.GetDataOne(
                                                                  x => x.NoSPK == DeliveryOrderDTO.Spk.NoSPK);
                                                          if (spk != null)
                                                          {
                                                              spk.Status = Convert.ToInt16(Status.Close);
                                                              _SpkRepository.SaveOrUpdate(spk);
                                                          }
                                                      }
                                                  });

                res = true;
            }
            catch (Exception ex)
            {
                res = false;
                throw ex;
            }

            return res;
        }


        public bool Delete(DeliveryOrderDTO DeliveryOrderDto)
        {
            bool res;
            try
            {
                DeliveryOrder DeliveryOrder = DeliveryOrderRepository.GetDataOne(x => x.DONo == DeliveryOrderDto.DONo);
                
                DeliveryOrderRepository.ExecuteTransactionNative(
                    () =>
                        {
                            _mutasiStokRepository.DeleteMutasiStok(DeliveryOrder.DONo);
                            //balik QtyOnHandnya 
                            //foreach (var DoDetail in DeliveryOrder.DeliveryOrderDetails)
                            //{
                            //    var inventoryWarehouse = _iwRepository.GetDataOne(x => x.SerialNumber == DoDetail.Inventory.SerialNumber && x.KodeWarehouse == DoDetail.Warehouse.KodeWarehouse);
                            //    if (inventoryWarehouse == null) inventoryWarehouse = new InventoryWarehouse();
                            //    inventoryWarehouse.Sheet += DoDetail.Tinggi;
                            //    inventoryWarehouse.Qty += DoDetail.QtyUnit;
                            //    _iwRepository.SaveOrUpdate(inventoryWarehouse);
                            //}
                            DeliveryOrder.Status = 2;
                            DeliveryOrderRepository.SaveOrUpdate(DeliveryOrder);
                            //Release SO
                            if (DeliveryOrder.SalesOrder != null)
                            {
                                var SO = _SORepository.GetDataOne(x => x.SONo == DeliveryOrder.SalesOrder.SONo);
                                SO.Status = (int) Status.Open;
                                _SORepository.SaveOrUpdate(SO);
                            }
                        }
                    );

                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public List<DeliveryOrderDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression, int page,
                                                        out long recordCount)
        {
            var DeliveryOrders = new List<DeliveryOrder>();
            var Results = new List<DeliveryOrderDTO>();
            DeliveryOrders = DeliveryOrderRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = DeliveryOrderRepository.RecordCount;
            foreach (var d in DeliveryOrders)
            {
                var Dto = new DeliveryOrderDTO();
                Dto.DONo = d.DONo;
                Dto.DODate = d.DODate;
                Dto.Description = d.Description;
                Dto.DeliveryAddress = d.DeliveryAddress;
                Dto.CustomerName = d.CustomerName;
                Dto.Address = d.Address;
                Dto.Telp = d.Telp;
                Dto.SONo = d.SONo;
                Dto.Status = (Status)d.Status;
                Dto.PSNo = d.PSNo;
                Dto.SINo = d.SINo;
                Results.Add(Dto);
            }
            return Results;
        }


        public List<DeliveryOrderDTO> GetAllDeliveryOrder()
        {
            List<DeliveryOrder> DeliveryOrders =
                DeliveryOrderRepository.GetDataList(x => x.Status == Convert.ToInt16(Status.Open)).ToList();
            IEnumerable<DeliveryOrderDTO> Results = from d in DeliveryOrders
                                                    select new DeliveryOrderDTO {DONo = d.DONo};

            return Results.ToList();
        }


        public DeliveryOrderDTO GetDeliveryOrder(String kodeDeliveryOrder)
        {
            DeliveryOrder deliveryOrder = DeliveryOrderRepository.GetDataOne(x => x.DONo == kodeDeliveryOrder);
            var deliveryOrderDto = new DeliveryOrderDTO();
            deliveryOrderDto.InjectFrom<CloneInjection>(deliveryOrder);
            return deliveryOrderDto;
        }

        public List<DeliveryOrderDTO> GetDeliveryOrderList(string NODO)
        {
            List<DeliveryOrder> DeliveryOrders =
                DeliveryOrderRepository.GetDataList(x => x.DONo.Contains(NODO)).ToList();
            var Results = new List<DeliveryOrderDTO>();
            DeliveryOrders.ForEach(x =>
                                       {
                                           var deliveryOrderDto = new DeliveryOrderDTO();
                                           deliveryOrderDto.InjectFrom<CloneInjection>(x);
                                           Results.Add(deliveryOrderDto);
                                       }
                );

            return Results;
        }


        public string GetLastDONo(CostCenterDTO costCenter)
        {
            var appParamServices = new AppParamServices();
            AppParamDTO param = appParamServices.GetAppParamList("KodeDO").FirstOrDefault();
            string res = DeliveryOrderRepository.GetMaxNumber(costCenter.CostCenterId, param.AppParamValue);
           
            if (string.IsNullOrEmpty(res))
                res =  param.AppParamValue;

            string formatSO = "0000";
            string lastNo = string.Empty;
            string kodeSO;
            if (res.Length <= 4)
            {
                lastNo = formatSO;
                kodeSO = res;
            }
            else
            {
                lastNo = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[3];
                kodeSO = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(lastNo) + 1).ToString().Length) +
                           (int.Parse(lastNo) + 1);
            
            return kodeSO + "/" + costCenter.CostCenterId + "/" + DateTime.Now.Year + "/" + soNum;
        }


        public bool DeleteDetail(DeliveryOrderDetailDTO deliveryOrderDetailDto)
        {
            bool res;
            try
            {
                var DODetail =
                    DeliveryOrderRepository.Session.Get<DeliveryOrderDetail>(
                        deliveryOrderDetailDto.DeliveryOrderDetailId);
                DeliveryOrderRepository.ExecuteTransactionNative(
                    () =>
                        {
                            _mutasiStokRepository.DeleteMutasiStok(deliveryOrderDetailDto.DoNo,
                                                                   deliveryOrderDetailDto.Inventory.SerialNumber);
                            DeliveryOrderRepository.DeleteDetail(DODetail, deliveryOrderDetailDto.DeliveryOrderDetailId);
                        });

                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }

        public bool SendEmail(DeliveryOrderDTO deliveryOrderDto, String DestinationFolder)
        {
            var mailServices = new MailServices();
            DeliveryOrder deliveryOrder = DeliveryOrderRepository.GetDataOne(x => x.DONo == deliveryOrderDto.DONo);
            deliveryOrderDto = Mapper.Map(deliveryOrder, deliveryOrderDto);
            return mailServices.SendEmail(deliveryOrderDto,DestinationFolder);
        }


        public List<DeliveryOrderDTO> GetAllDeliveryOrderByCostCenter(CostCenterDTO costCenter)
        {
            if (costCenter == null) return new List<DeliveryOrderDTO>();
            IList<DeliveryOrder> DeliveryOrders =
                DeliveryOrderRepository.GetDataList(
                    x =>
                    x.Status == Convert.ToInt16(Status.Open) && x.CostCenter.CostCenterId == costCenter.CostCenterId);
            IEnumerable<DeliveryOrderDTO> Results = from d in DeliveryOrders
                                                    select new DeliveryOrderDTO {DONo = d.DONo,DODate = d.DODate};

            return Results.ToList();
        }

        #endregion
    }
}